package io.renren.modules.iots.utils.comment;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.renren.modules.iots.utils.socket.client.SocketBean;
import io.renren.modules.iots.utils.socket.client.SocketUtils;

/**
 * 拼接接收到的消息
 * 
 * @author zhouxidong
 *
 */
public class Msg_rellect {

	/**
	 * 日志
	 */
	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 存放收集到的byte[]信息
	 */
	private List<Byte> rellect_list = new ArrayList<>();

	/**
	 * 消息体的长度
	 */
	private Integer bodylength = 0;

	/**
	 * 需要拼接的byte数组
	 */
	private byte[] rellect_byte = null;

	/**
	 * rellect_byte的指针
	 */
	private int rellect_point = 0;

	/**
	 * 储存已经拼接好的byte数组
	 */
	private List<byte[]> result = new ArrayList<>();

	/**
	 * 是否可以向rellect_byte中复制数据
	 */
	private boolean enable = false;

	/**
	 * 程序是否准备就绪
	 */
	public boolean isok = true;

	/**
	 * 拼接接收到的信息
	 * 
	 * @param data
	 * @return
	 */
	public List<byte[]> rellect(byte[] data) {
		isok = false;
		// 检查是否满足拼接条件
		if (check_before()) {
			linked(data);
			List<byte[]> list = new ArrayList<>();
			list.addAll(result);
			if (!list.isEmpty()) {
				this.result.clear();
				isok = true;
				return list;
			}
			isok = true;
		} else {
			isok = true;
		}
		return null;
	}

	/**
	 * 检查是否满足拼接条件
	 * 
	 * @return
	 */
	private boolean check_before() {
		if (this.bodylength <= 8192 && this.bodylength >= 0) {// 满足这个条件说明已经确定消息体长度，可以拼接
			return true;
		} else { // 满足这个条件说明通讯出现了异常
			// 重新连接
			relink();
			// 初始化Msg_rellect
			init_Msg_rellect();
			return false;
		}
	}

	/**
	 * socket重连
	 */
	private void relink() {
		Map<SocketBean, Msg_rellect> map = SocketUtils.RELLECTMESSAGE;
		// 重新连接socket
		for (SocketBean sb : map.keySet()) {
			if (map.get(sb) == this) {
				String address = sb.getServerip() + ":" + sb.getServerport();
				try {
					logger.error("地址为：" + address + "的服务端出现异常，需要断开重连！！");
					sb.getSocketChannel().close();
					sb.getSelectionKey();
					logger.error(address + "已经断开，正在重连");
					sb.setConnectstatus(2);
					sb.initialize();
				} catch (IOException e) {
					try {
						sb.getSocketChannel().close();
					} catch (IOException e1) {
						logger.error("地址为：" + address + "的服务端断开出现异常！！");
					}
				}
				// 跳出循环
				break;
			}
		}
	}

	/**
	 * 初始化Msg_rellect
	 */
	private void init_Msg_rellect() {
		// 正常复位
		reset();
		this.rellect_list.clear();
		this.result.clear();
	}

	/**
	 * 正常复位
	 */
	private void reset() {
		this.enable = false;
		this.bodylength = 0;
		this.rellect_point = 0;
		this.rellect_byte = null;
	}

	/**
	 * 拼接传入的字节数组
	 * 
	 * @param data
	 */
	private void linked(byte[] data) {
		// 将传入的字节数组添加到this.rellect_list中
		for (Byte b : data) {
			this.rellect_list.add(b);
		}
		// 循环拷贝数据
		while (rellect_list.size() > 160) {
			cycle_copy();
		}
	}

	/**
	 * @author 周西栋 @date 2018年6月21日 @Title: cycle_copy @Description:
	 * 循环拷贝数据 @param 参数 @return void 返回类型 @throws
	 */
	private void cycle_copy() {
		if (bodylength == 0) {// 初始化或重新开始
			if (this.rellect_list.size() > 160) {
				byte[] new_body_length = new byte[4];
				new_body_length[0] = this.rellect_list.get(156);
				new_body_length[1] = this.rellect_list.get(157);
				new_body_length[2] = this.rellect_list.get(158);
				new_body_length[3] = this.rellect_list.get(159);
				int length = Hex.byteArrayToIntDesc(new_body_length, 4);
				if ((length > 8192) || (length <= 0)) {
					// 出现异常，重连
					relink();
					init_Msg_rellect();
				} else {// 满足条件，为this.bodylength赋值
					this.bodylength = length;
					// 创建需要接收的byte数组
					rellect_byte = new byte[162 + this.bodylength];
					// 指针复位
					this.rellect_point = 0;
					// 改变可复制标记
					this.enable = true;
					// 将this.rellect_list中的
					copy_data();
				}
			}
		} else {
			if (this.rellect_point < rellect_byte.length) {
				// 改变可复制标记
				this.enable = true;
			} else {
				// 改变可复制标记
				this.enable = false;
			}
			// 将this.rellect_list中的
			copy_data();
		}
	}

	/**
	 * @author 周西栋 @date 2018年6月21日 @Title: copy_data @Description:
	 * 将rellect_list里的数据转到rellect_byte中 @param 参数 @return void 返回类型 @throws
	 */
	private void copy_data() {
		while (enable && rellect_list.size() > 0) {
			this.rellect_byte[this.rellect_point] = this.rellect_list.get(0);
			this.rellect_list.remove(0);
			this.rellect_point++;
			if (this.rellect_point == rellect_byte.length) {
				enable = false;
				// 先将数据转移
				byte[] copy = new byte[this.rellect_byte.length];
				for (int i = 0; i < copy.length; i++) {
					copy[i] = this.rellect_byte[i];
				}
				// 当拼接完整后，将拼接完当放入this.result中
				this.result.add(copy);
				// 复位
				reset();
			}
		}
	}

}
